package com.zxq.common.utils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.DataFormatException;
import java.util.zip.Deflater;
import java.util.zip.Inflater;

/**
 * 功能：数据流压缩与解压<br>
 * 介绍：<br>
 * 1. deflate是zip压缩文件的默认算法. 其实deflate现在不光用在zip文件中, 在7z,xz等其他的压缩文件中都用.<br>
 * 2. 实际上deflate只是一种压缩数据流的算法. 任何需要流式压缩的地方都可以用<br>
 * 3. 可以指定算法的压缩级别，这样你可以在压缩时间和输出文件大小上进行平衡。可选的级别有0（不压缩），以及1(快速压缩)到9（慢速压缩）,这里使用的是以速度为优先。<br>
 * 压缩比：<br>
 * - 字节数	压缩比率	    耗费时间<br>
 * - 10	    19/11	    ~7000us<br>
 * - 101	109/101	    ~8500us<br>
 * - 1500	124/1501	~10000us<br>
 *
 * 场景举例：Redis等存储数据的场景，通过压缩避免大对象<br>
 *
 * 对比：<br>
 * - deflate：最常见的无损压缩算法，非常关键。<br>
 * - .zip：archive format，使用了deflate压缩算法<br>
 * - .gz(或gzip格式）: single file compress format，也是使用了deflate压缩算法<br>
 * - .tar.gz或.tgz：archive format，可认为.gz文件的集合，但又不止是多个.gz的集合，因为tgz利用了文件之间的关联信息，提升了压缩率。<br>
 * - zlib：一个通用库，只有源代码，不提供可执行文件，支持gzip。linux内核、libpng、git等等都用了它。<br>
 * - gzip：GNU Gzip，开源，提供了gzip和gunzip可执行文件，直接可以用来压缩、解压缩。内部也是实现了deflate算法。<br>
 * - 7-Zip：类似gzip，也是工具<br>
 */
@SuppressWarnings("unused")
public class DeflateUtil {

    /**
     * 压缩
     *
     * @param input 入参：byte数组
     * @return 压缩后的byte数组
     * @throws IOException IO异常
     */
    public static byte[] compress(byte[] input) throws IOException {
        if (input == null || input.length == 0) {
            return new byte[0];
        }

        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            Deflater compressor = new Deflater(6);
            compressor.setInput(input);
            compressor.finish();
            final byte[] buf = new byte[2048];
            while (!compressor.finished()) {
                int count = compressor.deflate(buf);
                bos.write(buf, 0, count);
            }
            compressor.end();

            return bos.toByteArray();
        }
    }

    /**
     * 解压
     *
     * @param input byte[]
     * @return 解压后的byte[]
     * @throws IOException IO异常
     * @throws DataFormatException 格式不识别异常
     */
    public static byte[] uncompress(byte[] input) throws IOException, DataFormatException {
        if (input == null || input.length == 0) {
            return new byte[0];
        }

        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
            Inflater decompressor = new Inflater();
            decompressor.setInput(input);
            final byte[] buf = new byte[2048];
            while (!decompressor.finished()) {
                int count = decompressor.inflate(buf);
                bos.write(buf, 0, count);
            }
            decompressor.end();

            return bos.toByteArray();
        }
    }
}

